/*!
 * Node-insertion module v1.0.0 of jRaiser javascript library
 * http://code.google.com/p/jraiser/
 *
 * Author: Heero.Luo
 * Licensed under MIT license
 *
 * Date: Tue Jun 05 2012 10:37:32 GMT+0800
 */
define(function(require, exports, module) { 'use strict';

var core = require('core/1.0.x/core'), $base = require('node-base/1.0.x/node-base');


/**
 * 根据HTML创建节点
 * @param {String} HTML代码
 * @param {DOMDocument} 节点所属文档对象，默认为当前文档对象
 * @return {Array} 节点数组
 */
function createNodes(html, ownerDocument) {
	var div = (ownerDocument || document).createElement('div'), result = [ ];
	div.innerHTML = html;
	
	var child = div.firstChild;
	while (child) {
		result.push( child.cloneNode(true) );
		child = child.nextSibling;
	}
	
	div = null;
	
	return result;
}
/**
 * 创建包含指定节点的文档片段
 * @param {Array<DOMElement>} 文档片段包含的节点
 * @param {DOMDocument} 文档片段所属的文档对象，默认为当前文档对象
 * @return {DOMFragment} 文档片段
 */
function buildFragment(nodes, ownerDocument) {
	var frag = (ownerDocument || document).createDocumentFragment();
	nodes.forEach(function(node) {
		frag.appendChild(node);
	});
	
	return frag;
}

// 如果有多个节点，返回包含这几个节点的文档片段；
// 如果只有一个节点，则返回此节点
function explainNodes(nodes, ownerDocument) {
	if (typeof nodes === 'string') {
		nodes = createNodes(nodes, ownerDocument);
	} else if ( $base.isNode(nodes) ) {
		return nodes;
	}
	
	return nodes.length > 1 ? buildFragment(nodes, ownerDocument) : nodes[0];
}


/**
 * 把目标节点插入为参考节点的最后一个子节点
 * @param {String|DOMElement|Array<DOMElement>|DOMFragment} 目标节点
 * @param {DOMElement} 参考节点
 * @param {Boolean} 此参数仅用于在循环调用中忽略对目标节点的重复解析
 * @return {DOMElement|DOMFragment} 目标节点
 */
function appendChild(targetNodes, parentNode, isPass) {
	if (!isPass) { targetNodes = explainNodes(targetNodes, parentNode.ownerDocument); }
	
	parentNode.appendChild(targetNodes);
	
	return targetNodes;
}
/**
 * 把目标节点插入为参考节点的第一个子节点
 * @param {String|DOMElement|Array<DOMElement>|DOMFragment} 目标节点
 * @param {DOMElement} 参考节点
 * @param {Boolean} 此参数仅用于在循环调用中忽略对目标节点的重复解析
 * @return {DOMElement|DOMFragment} 目标节点
 */
function prependChild(targetNodes, parentNode, isPass) {
	if (!isPass) { targetNodes = explainNodes(targetNodes, parentNode.ownerDocument); }
	
	var firstChild = parentNode.firstChild;
	if (firstChild) {
		parentNode.insertBefore(targetNodes, firstChild);
	} else {
		parentNode.appendChild(targetNodes);
	}
	
	return targetNodes;
}
/**
 * 在参考节点之前插入目标节点
 * @param {String|DOMElement|Array<DOMElement>|DOMFragment} 目标节点
 * @param {DOMElement} 参考节点
 * @param {Boolean} 此参数仅用于在循环调用中忽略对目标节点的重复解析
 * @return {DOMElement|DOMFragment} 目标节点
 */
function insertBefore(targetNodes, refNode, isPass) {
	if (!isPass) { targetNodes = explainNodes(targetNodes, refNode.ownerDocument); }
	
	refNode.parentNode.insertBefore(targetNodes, refNode);
	
	return targetNodes;
}
/**
 * 在参考节点之后插入目标节点
 * @param {String|DOMElement|Array<DOMElement>|DOMFragment} 目标节点
 * @param {DOMElement} 参考节点
 * @param {Boolean} 此参数仅用于在循环调用中忽略对目标节点的重复解析
 * @return {DOMElement|DOMFragment} 目标节点
 */
function insertAfter(targetNodes, refNode, isPass) {
	if (!isPass) { targetNodes = explainNodes(targetNodes, refNode.ownerDocument); }

	var parentNode = refNode.parentNode, nextSibling = refNode.nextSibling;
	if (nextSibling) {
		parentNode.insertBefore(targetNodes, nextSibling);
	} else {
		parentNode.appendChild(targetNodes);
	}
	
	return targetNodes;
}
/**
 * 把参考节点替换成目标节点
 * @param {String|DOMElement|Array<DOMElement>|DOMFragment} 目标节点
 * @param {DOMElement} 参考节点
 * @param {Boolean} 此参数仅用于在循环调用中忽略对目标节点的重复解析
 * @return {DOMElement|DOMFragment} 目标节点
 */
function replaceWith(targetNodes, refNode, isPass) {
	if (!isPass) { targetNodes = explainNodes(targetNodes, refNode.ownerDocument); }
	
	refNode.parentNode.replaceChild(targetNodes, refNode);
}


core.extend(exports, {
	/**
	 * See line 15
	 */
	create : createNodes,
	
	/**
	 * See line 35
	 */
	buildFragment : buildFragment,
	
	/**
	 * See line 63
	 */
	appendChild : appendChild,
	
	/**
	 * See line 77
	 */
	prependChild : prependChild,
	
	/**
	 * See line 96
	 */
	insertBefore : insertBefore,
	
	/**
	 * See line 110
	 */
	insertAfter : insertAfter,

	/**
	 * See line 129
	 */
	replaceWith : replaceWith,
	
	/**
	 * node模块的扩展接口
	 */
	nodeApis : {
		/**
		 * 对指定节点进行操作
		 * @param {String|DOMElement|Array<DOMElement>|DOMtFragment} 节点
		 * @param {Function} 操作函数
		 * @param {Function} 操作条件，如果此参数不为空且返回值为false，则不进行操作
		 * @return {NodeList} 当前节点集合
		 */
		_doWithGivenNodes : function(nodes, fn, condition) {
			var targetNodes;
			
			this.forEach(function(refNode, i) {
				if (!condition || condition.apply(this, arguments) !== false) {
					if (!targetNodes) { targetNodes = explainNodes(nodes); }
					fn.call(this, i > 0 ? targetNodes.cloneNode(true) : targetNodes, refNode);
				}
			});
			
			targetNodes = null;
			
			return this;
		},
		
		/**
		 * 把目标节点（或其克隆节点）插入为当前所有节点的最后一个子节点
		 * @param {String|DOMElement|Array<DOMElement>|DOMtFragment} 目标节点
		 * @return {NodeList} 当前节点集合
		 */
		appendChild : function(nodes) {
			return this._doWithGivenNodes(nodes, function(targetNodes, refNode) {
				appendChild(targetNodes, refNode, true);
			}, function(refNode) {
				return refNode.nodeType === 1;
			});
		},
		
		/**
		 * 把目标节点（或其克隆节点）插入为当前所有节点的第一个子节点
		 * @param {String|DOMElement|Array<DOMElement>|DOMtFragment} 目标节点
		 * @return {NodeList} 当前节点集合
		 */
		prependChild : function(nodes) {
			return this._doWithGivenNodes(nodes, function(targetNodes, refNode) {
				prependChild(targetNodes, refNode, true);
			}, function(refNode) {
				return refNode.nodeType === 1;
			});
		},
		
		/**
		 * 在当前所有节点之后插入目标节点（或其克隆节点）
		 * @param {String|DOMElement|Array<DOMElement>|DOMtFragment} 目标节点
		 * @return {NodeList} 当前节点集合
		 */
		insertAfter : function(nodes) {
			return this._doWithGivenNodes(nodes, function(targetNodes, refNode) {
				insertAfter(targetNodes, refNode, true);
			});
		},
		
		/**
		 * 在当前所有节点之前插入目标节点（或其克隆节点）
		 * @param {String|DOMElement|Array<DOMElement>|DOMtFragment} 目标节点
		 * @return {NodeList} 当前节点集合
		 */
		insertBefore : function(nodes) {
			return this._doWithGivenNodes(nodes, function(targetNodes, refNode) {
				insertBefore(targetNodes, refNode, true);
			});
		},
		
		/**
		 * 在当前所有节点替换为目标节点（或其克隆节点）
		 * @param {String|DOMElement|Array<DOMElement>|DOMtFragment} 目标节点
		 * @return {NodeList} 当前节点集合
		 */
		replaceWith : function(nodes) {
			return this._doWithGivenNodes(nodes, function(targetNodes, refNode) {
				replaceWith(targetNodes, refNode, true);
			});
		},
		
		/**
		 * 把当前所有节点从其文档树中移除
		 * @return {NodeList} 当前节点集合
		 */
		detach : function() {
			this.forEach(function(elt) { elt.parentNode.removeChild(elt); });
			
			return this;
		}
	}
});

});